package com.jastar.android.jigsaw;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.jastar.android.jigsaw.item.IndexBitmap;
import com.jastar.android.jigsaw.item.JigsawImage;

import java.util.Arrays;
import java.util.Collections;
import java.util.stream.IntStream;


public class JigsawView extends View {

    private Paint normalPaint, selectPaint, currentPaint;
    public IndexBitmap[] cards;
    private int selectCard, selectMode, currentCard;
    private int card_w, card_h;
    private int xNum, yNum;
    private FinishHandler finishHandler;
    private boolean isFinish;
    private final Rect selectRect = new Rect();
    private final Rect currentRect = new Rect();

    public JigsawView(Context context) {
        super(context);
        init();
    }

    public JigsawView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        normalPaint = new Paint();
        normalPaint.setStyle(Paint.Style.STROKE);
        normalPaint.setColor(0xFF333333);
        normalPaint.setStrokeWidth(2);

        selectPaint = new Paint();
        selectPaint.setStyle(Paint.Style.STROKE);
        selectPaint.setColor(0xFFFF6666);
        selectPaint.setStrokeWidth(6);

        currentPaint = new Paint();
        currentPaint.setStyle(Paint.Style.STROKE);
        currentPaint.setColor(0xFFFFDD66);
        currentPaint.setStrokeWidth(6);
    }

    public void setFinishHandler(FinishHandler finishHandler) {
        this.finishHandler = finishHandler;
    }

    public void initImage(JigsawImage image) {
        if (image.getxNum() < 2 || image.getyNum() < 2) throw new RuntimeException("Illegal size.");
        this.xNum = image.getxNum();
        this.yNum = image.getyNum();

        isFinish = false;
        selectCard = -1;
        selectMode = 0;
        currentCard = 0;
        cards = new IndexBitmap[xNum * yNum];
        Bitmap sourceBitmap = BitmapFactory.decodeResource(getResources(), image.getImageId());

        ViewGroup.LayoutParams params = this.getLayoutParams();
        int w = params.width, h = params.height;
        params.width = Math.min(w, h * sourceBitmap.getWidth() / sourceBitmap.getHeight());
        params.height = Math.min(h, w * sourceBitmap.getHeight() / sourceBitmap.getWidth());
        setLayoutParams(params);
        Bitmap bitmap = Bitmap.createScaledBitmap(sourceBitmap, params.width, params.height, false);

        card_w = bitmap.getWidth() / xNum;
        card_h = bitmap.getHeight() / yNum;
        int index = 0;
        for (int yi = 0; yi < yNum; yi++) {
            for (int xi = 0; xi < xNum; xi++) {
                cards[index] = new IndexBitmap(index, Bitmap.createBitmap(bitmap, xi * card_w, yi * card_h, card_w, card_h));
                index++;
            }
        }
        Collections.shuffle(Arrays.asList(cards));
    }

    @Override
    protected void onDraw(@NonNull Canvas canvas) {
        if (null == cards) return;
        for (int i = 0; i < cards.length; i++) {
            Bitmap card = cards[i].getBitmap();
            int l = i % xNum * card_w, t = i / xNum * card_h;
            canvas.drawBitmap(card, l, t, null); //画图片
            if (isFinish) continue;

            int r = l + card.getWidth(), b = t + card.getHeight();
            canvas.drawRect(l, t, r, b, normalPaint); //画边框
            if (selectMode == 1) { //整列
                t = 0;
                b = yNum * card_h;
            } else if (selectMode == 2) { //整行
                l = 0;
                r = xNum * card_w;
            }
            if (i == selectCard) selectRect.set(l, t, r, b);
            if (i == currentCard) currentRect.set(l, t, r, b);
        }
        if (selectCard >= 0) canvas.drawRect(selectRect, selectPaint);
        if (isFinish) canvas.drawRect(0, 0, getWidth(), getHeight(), normalPaint);
        else canvas.drawRect(currentRect, currentPaint);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (isFinish) return super.onKeyDown(keyCode, event);
        int newCard = currentCard;
        switch (keyCode) {
            case KeyEvent.KEYCODE_DPAD_LEFT:
                if (currentCard % xNum > 0) newCard--;
                break;
            case KeyEvent.KEYCODE_DPAD_RIGHT:
                if (currentCard % xNum < xNum - 1) newCard++;
                break;
            case KeyEvent.KEYCODE_DPAD_UP:
                if (currentCard >= xNum) newCard -= xNum;
                break;
            case KeyEvent.KEYCODE_DPAD_DOWN:
                if (currentCard < xNum * (yNum - 1)) newCard += xNum;
                break;
            case KeyEvent.KEYCODE_DPAD_CENTER:  //一般遥控的确认键
            case KeyEvent.KEYCODE_BUTTON_1:     //某些设备的确认键
            case KeyEvent.KEYCODE_ENTER:        //回车，兼容模拟器调试
                if (selectCard < 0) selectCard = currentCard;
                else if (selectCard == currentCard) selectMode = (selectMode + 1) % 3;
                else exchangeCard();
                invalidate();
                return true;
            default:
                return super.onKeyDown(keyCode, event);
        }

        if (newCard != currentCard) {
            currentCard = newCard;
            invalidate();
            return true;
        }
        return super.onKeyDown(keyCode, event);

    }

    private void exchangeCard() {
        switch (selectMode) {
            case 1: { //整列
                int[] selCards = getColCards(selectCard);
                int[] curCards = getColCards(currentCard);
                if (selCards.length != curCards.length) throw new RuntimeException("交换图片异常:错误的行列数据.");
                IntStream.range(0, selCards.length).forEach(i -> exchange(selCards[i], curCards[i]));
                break;
            }
            case 2: { //整行
                int[] selCards = getRowCards(selectCard);
                int[] curCards = getRowCards(currentCard);
                if (selCards.length != curCards.length) throw new RuntimeException("交换图片异常:错误的行列数据.");
                IntStream.range(0, selCards.length).forEach(i -> exchange(selCards[i], curCards[i]));
                break;
            }
            case 0: //单选
            default:
                exchange(selectCard, currentCard);
        }
        selectCard = -1;
        if (judgeFinish()) {
            isFinish = true;
            if (null != finishHandler) finishHandler.onFinish();
        }
    }

    private int[] getRowCards(int index) {
        int[] res = new int[xNum];
        int start = index / xNum * xNum;
        IntStream.range(0, xNum).forEach(i -> res[i] = start + i);
        return res;
    }

    private int[] getColCards(int index) {
        int[] res = new int[yNum];
        IntStream.range(0, yNum).forEach(i -> res[i] = index % xNum + xNum * i);
        return res;
    }

    private void exchange(int indexA, int indexB) {
        IndexBitmap card = cards[indexA];
        cards[indexA] = cards[indexB];
        cards[indexB] = card;
    }

    private boolean judgeFinish() {
        if (null == cards) return false;
        for (int i = 0; i < cards.length; i++) {
            if (i != cards[i].getIndex()) return false;
        }
        return true;
    }

    interface FinishHandler {
        void onFinish();
    }

}